
from rdflib.sparql.bison.IRIRef import RemoteGraph, NamedGraph
from rdflib.Graph import Graph
from rdflib.URIRef import URIRef

from Ft.Rdf.Parsers.Sparql.Processor import Processor

from nodetypes import config
from nodetypes.services import Query

from Ft.Server.Server.Rdf.Parsers.Sparql.Store import Store
from Ft.Server.Server.Rdf.Parsers.Sparql.Functions import Describe

class Describe(Describe):
    
    newGraph = Graph
    methodMap = {
        u'srx' : u'rdf',
        u'srj' : u'rdf',
    }
            
    def __init__(self, repo, urlFormatter, method=None):
        super(Describe,self).__init__(repo)
        self._newUrlMapper = urlFormatter.newUrlMapper
        self._method = method or u'rdf'
        
    def describeResourceUris(self, graph, resources, resultGraph):
                
        from myelin.rdf.Ns import RDFS_ISDEFINEDBY, RDFS_SEEALSO
        RDFS_ISDEFINEDBY = URIRef(RDFS_ISDEFINEDBY)
        RDFS_SEEALSO = URIRef(RDFS_SEEALSO)
        
        g_op = resultGraph.add
                      
        publicUrl = self._newUrlMapper(
            True,
            action='view',
            method=None
        )
        describeUrl = self._newUrlMapper(
            True,
            action='view',
            method=self._method
        )
        
        for res in resources:
            furi = res._path.absolutePathAsUri
            
            s = URIRef(res.uri)
            
            url = publicUrl(furi)
            if url:
                g_op((
                    s,
                    RDFS_ISDEFINEDBY,
                    URIRef(url)
                ))
            
            url = describeUrl(furi)
            if url:
                g_op((
                    s,
                    RDFS_SEEALSO,
                    URIRef(url)
                ))
        

class Service(object):    
    
    newProcessor = Processor
    newStore = Store
    
    newRemoteGraph = RemoteGraph
    newNamedGraph = NamedGraph
    
    queryHelper = Query.Query()
    
    defaults = config.SERVICE_SPARQL_DEFAULTS
    defaultGraphMethodMap = config.SERVICE_SPARQL_GRAPH_METHOD_DEFAULTS
    
    newSPARQLDescribe = Describe
    
    extensionFunctions = {
    }
     
    def fetchParams(self, context, source, params, errors):
        return params, errors
    
    def getExtensionFunctions(self, context, params, extFuncs):
        from rdflib import sparql
        extFuncs[sparql.DESCRIBE] = self.newSPARQLDescribe(  
            context.repo,
            context.urlFormatter,
            params.get('graph-result-method') and params['graph-result-method'][0] or self.defaultGraphMethodMap.get(
                context.method
            )
        ).evaluate
        return extFuncs
    
    def execute(self, context, source):
        
        params, errors = self.fetchParams(
            context,
            source,
            {},
            {}
        )
        eventData = context.event.data        
        eventData.params = params
        eventData.errors = errors
        
        if errors:
            return False
        
        nsMaps = {}
        error = self.queryHelper.splitNsMaps(params['nsmaps'], nsMaps)
        if error:
            #print "Error NsMaps: %s" % nsMaps
            #print "msg: %s" % error
            errors['nsmaps'] = unicode(error)
            return False
        
        dbDriver, dbGraphs, dbGraphResolver, dbTextResolver = self.queryHelper.getDbSource(
            context.repo,
            eventData.config,
            context.account,
            context.acls,            
            context.defaults
        )
        
        # FIXME: dbTextResolver not used
        # need to add a TEXT_SEARCH function
        p = self.newProcessor(
            self.newStore(
                dbDriver, dbGraphResolver
            ), self.getExtensionFunctions(
                context,
                params,
                self.extensionFunctions.copy()
            )
        )
        
        overridingDataSets = set()        
        if params['default-graph-uri']:
            overridingDataSets.update(
                map(self.newRemoteGraph,params['default-graph-uri'])
            )
        
        if params['named-graph-uri']:
            overridingDataSets.update(
                map(self.newNamedGraph, params['named-graph-uri'])
            )
        
        try:            
            eventData.results = p.query(
                params['query'],
                initNs = nsMaps,
                overridingDataSets = overridingDataSets
            )
            return True
                
        except SyntaxError:
            if __debug__:
                import traceback
                traceback.print_exc()
            errors['query'] = u'syntax-error'            
        except:
            if __debug__:
                import traceback
                traceback.print_exc()
            errors['query'] = u'evaluate-error'
        
        return False
    
    
# cleanup
del RemoteGraph, \
    NamedGraph, \
    Processor, \
    config, \
    Query, \
    Store